from socket import *

from proto import session_package_pb2, session_auth_package_pb2, content_entity_pb2
import hashlib
import time

class SixinBuilder(object):
    def GetPingBuild(self):
        PingBytes = bytes([0x06, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
        # PingBytes = [0x06, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
        # for i in PingBytes:
        #     print(i)
        print('PingBytes -->', PingBytes)
        return PingBytes

    def SessionBuild(self, sessionpackageBytes):
        headerBytes = self.CreateHeader(sessionpackageBytes, 2)
        resultbytes = headerBytes
        resultbytes.extend(sessionpackageBytes)
        return resultbytes

    def SessionAuthBuild(self, sessionauthpackageBytes):
        headerBytes = self.CreateHeader(sessionauthpackageBytes, 1)
        resultbytes = headerBytes
        resultbytes.extend(sessionauthpackageBytes)
        return resultbytes

    def ContentBuild(self, contentpackageBytes):
        headerBytes = self.CreateHeader(contentpackageBytes, 1)
        resultbytes = headerBytes
        resultbytes.extend(contentpackageBytes)
        return resultbytes

    def CreateHeader(self, contentBytes, index):

        # b = bytes([1, 2, 3])
        # print('b -->', b)
        # exit()

        # bArr = bytearray([bytes(6), bytes(0), bytes(0), bytes(0), bytes(9), bytes(0), bytes(0), bytes(0), bytes(0), bytes(0), bytes(0), bytes(0)])
        bArr = bytearray([6, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0])
        print(len(bArr))

        length = len(contentBytes)
        b = length & 255
        b2 = (length >> 8) & 255
        b3 = (length >> 16) & 255
        print('contentBytes -->', type(contentBytes), contentBytes)
        a = self.GetMD5Digest_Bytes(contentBytes)
        if not a:
            return None
        # print('a[13].encode() -->', a[13].encode())
        # print('a -->', ord(a[13].encode()))

        bArr[2] = index
        bArr[5] = b3
        bArr[6] = b2
        bArr[7] = b
        bArr[9] = a[13]
        bArr[10] = a[14]
        bArr[11] = a[15]
        return bArr

    def GetMD5Digest_Bytes(self, plain):
        print('plain -->', plain)
        # plain = bytearray([0x06, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
        md5 = hashlib.md5(plain)
        result = md5.hexdigest()
        result_list = []
        for i in range(0, len(result), 2):
            result_list.append(int(result[i: i+2], 16))

        return bytes(result_list)

class CookieApp(object):
    def __init__(self, userid, sid, device_id, smid, to_userid, msg):
        # 账号uid
        # self.userid = "5f48643a000000000100690e"
        self.userid = userid

        # 账号sid
        # self.sessionid = "session.1598584160691585982619"
        self.sessionid = sid

        # 设备id
        # self.DeviceId = "ca93fbae-616f-340f-9258-17b600e564a2"
        self.DeviceId = device_id

        # 设备型号
        self.Model = "vivo"

        # app版本号
        self.VERSION_NAME = "6.30.0"

        # 手机系统版本
        self.OS_VERSION = "6.0.1"

        # Device_fingerprint
        # self.Device_fingerprint = "20200828083206ed83a108e400d6387539cbbe3f90ebbe01c8be0eb8be4d35"
        self.Device_fingerprint = smid

        # 接受消息的用户id
        # self.to_userid = "5ef0c195000000000101df16"
        self.to_userid = to_userid

        # 要发送的消息
        # self.msg = "你好"
        self.msg = msg

class XhsTcp(object):
    def __init__(self, cookie_app_obj, t=""):
        # self.cookie_app_obj = CookieApp()
        self.t = t
        self.user_auth = True
        self.disabled = False
        self.ok8 = False
        self.cookie_app_obj = cookie_app_obj
        self.tcp_socket = None
        self.socket_init()


    def socket_init(self):
        print("111111111111111")
        self.socket_connect()
        print("2222222222222222")
        self.socket_ping()
        print("33333333333333333")
        self.socket_session()
        result = self.socket_session_auth()

        if "user_id与session不符" in result or "session过期或校验失败" in result  or "封号" in result:
            # self.user_auth = False
            self.disabled = False
        else:
            if self.t in ["login", "send"]:
                self.socket_content_entity()
            else:
                self.ok8 = True

    def socket_recv(self):
        content = ""
        while True:
            result = self.tcp_socket.recv(10240)
            # print(len(result), result)
            if len(result) >= 12:
                content = result[12:]
                # print('content -->', content)
                content = content.decode('utf-8','ignore')
                print('content -->', content)
                break
            else:
                time.sleep(0.2)
        return content

    def socket_connect(self):
        # 1.创建tcp_client_socket 套接字对象
        self.tcp_socket = socket(AF_INET,SOCK_STREAM)
        # 作为客户端，主动连接服务器较多，一般不需要绑定端口

        # 2.连接服务器
        self.tcp_socket.connect(("129.211.152.148", 5333))

    def socket_ping(self):
        sixin_builder_obj = SixinBuilder()
        ret = self.tcp_socket.sendall(sixin_builder_obj.GetPingBuild())
        print('ret -->', ret)
        # print("发送成功")

        result = self.socket_recv()
        # result = self.tcp_socket.recv(1024)
        print('result -->', result)

    def socket_session(self):
        print("socket_session")
        # pers = demo1_pb2.SessionAuthPackage()
        sp_obj = session_package_pb2.SessionPackage()
        sp_obj.a = 2
        sp_obj.c = 1
        b = sp_obj.b.add()
        b.fromuid = self.cookie_app_obj.userid
        b.sid = self.cookie_app_obj.sessionid
        b.deviceId = self.cookie_app_obj.DeviceId
        b.d = "red"

        g = b.g.add()
        g.device_id = self.cookie_app_obj.DeviceId
        g.b = "phone"
        g.c = "Android"
        g.d = self.cookie_app_obj.Model
        g.e = self.cookie_app_obj.VERSION_NAME
        g.f = self.cookie_app_obj.OS_VERSION
        g.device_fingerprint = self.cookie_app_obj.Device_fingerprint

        # print('sp_obj -->', dir(sp_obj))
        sessionpackageBytes = sp_obj.SerializeToString()
        # sessionpackageBytes = sp_obj.Ser()
        # for index, i in enumerate(sessionpackageBytes):
        #     print('i -->', index, i)
        # print('sessionpackageBytes ==>', type(sessionpackageBytes))
        # print('sessionpackageBytes ==>', sessionpackageBytes)
        # print(len(sessionpackageBytes), sessionpackageBytes)
        sixin_builder_obj = SixinBuilder()
        sessionbytes = sixin_builder_obj.SessionBuild(sessionpackageBytes)
        # for index, i in enumerate(sessionbytes):
        #     print('i -->', index, i)
        # print('sessionbytes -->', len(sessionbytes), sessionbytes)
        ret = self.tcp_socket.sendall(sessionbytes)
        # print('ret -->', ret)

        result = self.socket_recv()

    def socket_session_auth(self):
        print("socket_session_auth")
        sapak_obj = session_auth_package_pb2.SessionAuthPackage()
        sapak_obj.c = 1
        b = sapak_obj.b.add()
        b.a = "{userid}-{timestamp}".format(
            userid=self.cookie_app_obj.userid,
            timestamp=int(round(time.time() * 1000))
        )
        b.fromuid = self.cookie_app_obj.userid
        b.sid = self.cookie_app_obj.sessionid
        b.e = "SessionAuth"
        b.f = "red"

        d = b.d.add()
        d.device_id = self.cookie_app_obj.DeviceId
        d.b = "phone"
        d.c = "Android"
        d.d = self.cookie_app_obj.Model
        d.e = self.cookie_app_obj.VERSION_NAME
        d.f = self.cookie_app_obj.OS_VERSION
        d.device_fingerprint = self.cookie_app_obj.Device_fingerprint

        hsabytes = sapak_obj.SerializeToString()
        # print('hsabytes -->', len(hsabytes), hsabytes)
        sixin_builder_obj = SixinBuilder()
        sessionauthbytes = sixin_builder_obj.SessionAuthBuild(hsabytes)
        ret = self.tcp_socket.sendall(sessionauthbytes)
        result = self.socket_recv()
        return result


    def socket_content_entity(self):
        print("socket_content_entity")
        timestamp = int(round(time.time() * 1000))
        # sx = content_entity_pb2.ContentEntity()

        # sx.j = None
        # sixinEntityBytes = sx.SerializeToString()

        sxp = content_entity_pb2.ContentPackage()
        sxp.c = 1
        # sxp.b = sx
        sx = sxp.b.add()
        sx.timestamp_fromid = "{timestamp}10000{fromid}".format(
            timestamp=timestamp,
            fromid=self.cookie_app_obj.userid
        )
        sx.timestamp = timestamp
        sx.uidexp = "{fromid}@red@phone@1".format(fromid=self.cookie_app_obj.userid)
        sx.fromuid = self.cookie_app_obj.userid
        sx.toid = self.cookie_app_obj.to_userid
        sx.txt = self.cookie_app_obj.msg
        sx.h = 1
        sx.i = False


        sxpBytes = sxp.SerializeToString()
        sixin_builder_obj = SixinBuilder()
        contentBytes = sixin_builder_obj.ContentBuild(sxpBytes)

        ret = self.tcp_socket.sendall(contentBytes)
        result = self.socket_recv()
        if "ok8" in result:
            self.ok8 = True
            print("发消息成功")
        elif "您的账号已封号，无法发布私信" in result:
            self.disabled = True


if __name__ == '__main__':
    ck_data = {'blogger_data': [], 'device_data': {"device_id": "bb42a2a1-7c4f-439d-b478-cc2b703a8328", "smid": "20200905094154e5df1044842ed38cdca60f05db08fbbb015ac6224f4b2ed8", "sid": "session.1599270147188477453846", "fid": "15992701091003fbc73890e5cef409a6b296d3b25741", "crypt_method": "901cdebafd9e113e", "phone": "16537387194", "register_time": "1598700447"}, 'blogger_id': '5f4a3b9f000000000100b719'}
    userid = ck_data['blogger_id']
    sid = ck_data['device_data']['sid']
    device_id = ck_data['device_data']['device_id']
    smid = ck_data['device_data']['smid']

    to_userid = "5cb54ef500000000170043f6"      # 张聪
    msg = "你好,可以加个关注不"

    cookie_app_obj = CookieApp(userid, sid, device_id, smid, to_userid, msg)
    obj = XhsTcp(cookie_app_obj)


# recv_data = tcp_client_socket.recv(1024)
# print('recv_data -->', recv_data)
# print('recv_data -->', recv_data.decode('utf-8', 'ignore'))
# tcp_client_socket.close()